package com.fingard.dsp.bank.directbank.jytpay01;

import com.fingard.constant.Format;
import com.fingard.dsp.bank.directConfig.ActSetItem;
import com.fingard.dsp.bank.directbank.DirectBase;
import com.fingard.net.WebRequest;
import com.fingard.text.Base64Helper;
import com.fingard.text.StringHelper;
import com.fingard.xml.XmlTextWriter;

import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Enumeration;
import java.util.Map;

/**
 * F.cruise
 * 金运通通用基类
 * -- 当前支持银谷收付费系统接入
 */
public class JYTPAY01Base extends DirectBase {
    /**
     * 获取字符编码
     *
     * @return 配置文件字符编码
     */
    protected String getCharset() {
        return getBankConfig().getCharset("UTF-8");
    }

    /**
     * 发送请求数据到金运通并获取返回数据
     *
     * @param xmlWriter
     * @param p_bankHeader
     * @throws Exception
     */
    protected void writeCommonHeader(XmlTextWriter xmlWriter, JYTPAY01Header p_bankHeader, ActSetItem actItem) throws Exception {
        if (StringHelper.isNullOrEmpty(p_bankHeader.tran_flowid)) {
            throw new Exception("未赋值tran_flowid");
        }

        if (StringHelper.isNullOrEmpty(p_bankHeader.tran_code)) {
            throw new Exception("未赋值tran_code");
        }

        xmlWriter.writeStartDocByDeclaration("<?xml version=\"1.0\" encoding=\"" + getCharset() + "\"?>");
        xmlWriter.writeStartElement("message");
        xmlWriter.writeStartElement("head");
        xmlWriter.writeElementString("version", "1.0.0");// 版本号
        xmlWriter.writeElementString("tran_type", "01");// 报文类型包括:	请求报文：01	响应报文：02
        xmlWriter.writeElementString("merchant_id", actItem.merchantId);// 商户号
        Date tmpDateNow = new Date();
        xmlWriter.writeElementString("tran_date", Format.Date8Format.format(tmpDateNow));// 交易日期
        xmlWriter.writeElementString("tran_time", Format.Time6Format.format(tmpDateNow));// 交易时间
        /*
         * 交易流水号，唯一标识一笔交易，必须以商户号开头。
         * 		单笔交易格式建议为：
         * 				商户号（12位）+ YYYYMMDDHHMMSS（14）+6位流水号
         * 		批量交易时，该流水号作为批次号且长度不能超过26，建议为：
         *				商户号（12位）+ YYYYMMDD（8）+6位流水号
         */
        xmlWriter.writeElementString("tran_flowid", p_bankHeader.tran_flowid);// 交易流水号
        xmlWriter.writeElementString("tran_code", p_bankHeader.tran_code);// 请求交易码
        xmlWriter.writeEndElement();
    }

    /**
     * 加密、签名
     *
     * @param p_reqXml 请求报文
     * @param actItem  证书、密钥
     * @return postStr[0]:报文密文    postStr[1]: 会话密钥密文   postStr[2]: 报文签名
     */
    protected String[] encryptAndSign(String p_reqXml, ActSetItem actItem) throws IOException {
        String[] postStr = new String[]{"", "", ""};

        String hexXmlEnc = "";
        String hexKeyEnc = "";
        String hexSign = "";

        RSAHelper rsaHelper = new RSAHelper();
        FileInputStream fis = null;
        FileInputStream fis1 = null;
        try {
            /*
             *  获取私钥
             */
            KeyStore ks = KeyStore.getInstance("PKCS12");

            fis = new FileInputStream(actItem.ownKeyStorePath);
            char[] keyPassword = null;
            if (StringHelper.hasAnyChar(actItem.ownKeyPassword)) {
                keyPassword = actItem.ownKeyPassword.toCharArray();
            }
            ks.load(fis, keyPassword);
            fis.close();
            fis = null;

            @SuppressWarnings("rawtypes")
            Enumeration enumAlias = ks.aliases();
            String keyAlias = null;
            if (enumAlias.hasMoreElements()) {
                keyAlias = (String) enumAlias.nextElement();
            }
            PrivateKey privateKey = (PrivateKey) ks.getKey(keyAlias, keyPassword);

            if (privateKey == null) {
                return null;
            }

            byte[] keyBytes = privateKey.getEncoded();
            // 私钥字符串
            String priKey = Base64Helper.getBase64(keyBytes);

            /*
             *  获取公钥
             */
            X509Certificate cert = null;
            fis1 = new FileInputStream(actItem.oppCertFilePath);
            CertificateFactory cf = CertificateFactory.getInstance("X509");
            cert = (X509Certificate) cf.generateCertificate(fis1);
            PublicKey publicKey = cert.getPublicKey();
            if (publicKey == null) {
                return null;
            }

            byte[] pkeyBytes = publicKey.getEncoded();
            // 公钥字符串
            String pubKey = Base64Helper.getBase64(pkeyBytes);

            rsaHelper.initKey(priKey, pubKey, 2048);

            // 明文加密
            hexXmlEnc = DESHelper.desEncryptToHex(p_reqXml, actItem.ownKeyPassword.getBytes());
            postStr[0] = hexXmlEnc;

            // 商户密钥加密
            byte[] bkey = rsaHelper.encryptRSA(actItem.ownKeyPassword.getBytes(), false, "utf-8");
            hexKeyEnc = DESHelper.hexEncode(bkey);
            postStr[1] = hexKeyEnc;

            // 报文签名
            byte[] sign = rsaHelper.signRSA(p_reqXml.getBytes("utf-8"), false, "utf-8");
            hexSign = DESHelper.hexEncode(sign);
            postStr[2] = hexSign;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                fis.close();
            }
            if (fis1 != null) {
                fis1.close();
            }
        }

        return postStr;
    }

    /**
     * 解密、验签
     *
     * @param hexXmlEnc 报文密文
     * @param hexKeyEnc 会话密钥密文
     * @param hexSign   签名
     * @return postStr[0]: 报文明文  postStr[1]:验签结果
     */
    protected String[] decryptAndVeriSign(String hexXmlEnc, String hexKeyEnc, String hexSign, ActSetItem actItem) throws IOException {
        String[] postStr = new String[]{"", ""};

        RSAHelper rsaHelper = new RSAHelper();
        FileInputStream fis = null;
        FileInputStream fis1 = null;
        try {
            /*
             * 获取私钥
             */
            KeyStore ks = KeyStore.getInstance("PKCS12");

            fis = new FileInputStream(actItem.ownKeyStorePath);
            char[] keyPassword = null;
            if (StringHelper.hasAnyChar(actItem.ownKeyPassword)) {
                keyPassword = actItem.ownKeyPassword.toCharArray();
            }
            ks.load(fis, keyPassword);
            fis.close();
            fis = null;

            @SuppressWarnings("rawtypes")
            Enumeration enumAlias = ks.aliases();
            String keyAlias = null;
            if (enumAlias.hasMoreElements()) {
                keyAlias = (String) enumAlias.nextElement();
            }
            PrivateKey privateKey = (PrivateKey) ks.getKey(keyAlias, keyPassword);

            if (privateKey == null) {
                return null;
            }

            byte[] keyBytes = privateKey.getEncoded();
            // 私钥字符串
            String priKey = Base64Helper.getBase64(keyBytes);

            /*
             * 获取公钥
             */
            X509Certificate cert = null;

            fis1 = new FileInputStream(actItem.oppCertFilePath);
            CertificateFactory cf = CertificateFactory.getInstance("X509");
            cert = (X509Certificate) cf.generateCertificate(fis1);
            fis1.close();

            PublicKey publicKey = cert.getPublicKey();
            if (publicKey == null) {
                return null;
            }

            byte[] pkeyBytes = publicKey.getEncoded();
            // 公钥字符串
            String pubKey = Base64Helper.getBase64(pkeyBytes);

            rsaHelper.initKey(priKey, pubKey, 2048);

            //  密钥解密
            byte[] bkey = rsaHelper.decryptRSA(DESHelper.hexDecode(hexKeyEnc), false, "utf-8");

            // 报文解密
            String xml = DESHelper.desDecryptFromHex(hexXmlEnc, bkey);
            postStr[0] = xml;

            // 验签
            byte[] bsign = DESHelper.hexDecode(hexSign);
            boolean ret = rsaHelper.verifyRSA(xml.getBytes("utf-8"), bsign, false, "utf-8");

            if (ret == true) {
                // 验签成功
                postStr[1] = "1";
            } else {
                // 验签失败
                postStr[1] = "0";
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                fis.close();
            }
            if (fis1 != null) {
                fis1.close();
            }
        }

        return postStr;
    }

    /**
     * http 发送金运通
     *
     * @param p_for    交易地址
     * @param p_reqMap http请求参数
     * @return http返回数据
     * @throws Exception
     */
    protected String[] sendToBank(String p_for, Map<String, String> p_reqMap) throws Exception {
        WriteBankLogLn2("提交金运通地址为：" + bankFront.getUrl(p_for));

        String p_reqStr = "";
        for (Map.Entry<String, String> postMap : p_reqMap.entrySet()) {
            if (!p_reqStr.equals("")) {
                p_reqStr += "&";
            }
            p_reqStr += postMap.getKey() + "=" + postMap.getValue();
        }

        // 发送金运通数据
        WriteBankLogStep2(p_reqStr);

        WebRequest tmpWebRequest = new WebRequest(bankFront.getUrl(p_for));
        tmpWebRequest.setConnectTimeout(60000);
        tmpWebRequest.setRequestProperty("connection", "Close");

        return tmpWebRequest.upload(p_reqStr.getBytes(getCharset()), getCharset());
    }
}
